package cn.txun05.csmall.commons.ex.handeler;


import cn.txun05.csmall.commons.ex.ServiceException;
import cn.txun05.csmall.commons.web.JsonResult;
import cn.txun05.csmall.commons.web.ServiceCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler
    public JsonResult handleServiceException(ServiceException e){
        log.warn("程序运行过程中出现了ServiceException,将统一处理");
        log.warn("异常信息：{}",e.getMessage());
        return JsonResult.fail(e.getServiceCode(),e.getMessage());
    }

    @ExceptionHandler
    public JsonResult handleBindException(BindException e){
        log.warn("程序运行过程中出现了BindException,将统一处理");
        log.warn("异常信息：{}",e.getMessage());
        //【解决方案1】使用1个字符串表示1个错误信息
        String message= e.getFieldError().getDefaultMessage();
        return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST,message);

        //【解决方案2】使用1个字符串表示错误信息
//        StringJoiner stringJoiner = new StringJoiner(",","请求参数错误,","!");
//        List<FieldError> fieldErrorList = e.getFieldErrors();
//        for (FieldError fieldError: fieldErrorList){
//            String s = fieldError.getDefaultMessage();
//            stringJoiner.add(s);
//        }
//        return stringJoiner.toString();

        //【解决方案3】使用集合表示多个信息，需要将当前方法的返回值类型声明为对应的集合类型
//        List<String> messageList = new ArrayList<>();
//        List<FieldError> fieldErrorList = e.getFieldErrors();
//        for(FieldError fieldError: fieldErrorList){
//            String s = fieldError.getDefaultMessage();
//            messageList.add(s);
//        }
//        return messageList;



    }
    @ExceptionHandler
    public JsonResult handleConstraintViolationException(ConstraintViolationException e){
        log.warn("程序运行过程中出现了ConstraintViolationException,将统一处理");
        log.warn("异常信息：{}",e.getMessage());
        String message = null;
        Set<ConstraintViolation<?>> constraintViolations =  e.getConstraintViolations();
        for (ConstraintViolation<?> constraintViolation:constraintViolations ){
            message=constraintViolation.getMessage();
        }
        return JsonResult.fail(ServiceCode.ERR_BAD_REQUEST,message);
    }
    // 如果@ExceptionHandler没有配置参数，则以方法参数的异常为准，来处理异常
   // 如果@ExceptionHandler配置了参数，则只处理此处配置的异常
    @ExceptionHandler(
            {BadCredentialsException.class,//处理密码错误异常
            InternalAuthenticationServiceException.class}//处理用户名不存在的异常
    )
    public JsonResult handleAuthenticationException(
            AuthenticationException e){
        log.warn("程序运行过程中出现了BadCredentialsException,将统一处理");
        log.warn("异常：",e);
        String message = "登录失败，用户名或者密码错误";
        return JsonResult.fail(ServiceCode.ERR_UNAUTHORIZED,message);
    }

    @ExceptionHandler
    public JsonResult handleDisabledException(
            DisabledException e){
        log.warn("DisabledException,将统一处理");
        log.warn("异常：",e);
        String message = "登录失败，账户失效";
        return JsonResult.fail(ServiceCode.ERR_UNAUTHORIZED_DISABLE,message);
    }

    @ExceptionHandler
    public JsonResult handleAccessDeniedException(
            AccessDeniedException e){
        log.warn("AccessDeniedException,将统一处理");
        log.warn("异常：",e);
        String message = "您当前登录的账户无权限，禁止访问";
        return JsonResult.fail(ServiceCode.ERR_FORBIDDEN,message);
    }


    //注意：在项目正式上线时，禁止使用e.printStackTrace()
    @ExceptionHandler
    public JsonResult handleThrowable(Throwable e){
        log.warn("程序运行过程中出现了Throwable,将统一处理");
        log.warn("异常信息：{}",e.getMessage());
        log.warn("异常：",e);//取代e.printStackTrace();效果相同，注意，第一个参数中不要使用{}进行占位
        String message = "服务器忙，请稍后再试！[在开发过程中，如果看到此提示，应该检查服务端的控制台，分析异常，并在全局异常处理器中补充处理对应异常的方法]";

//        JsonResult jsonResult = new JsonResult();
//        jsonResult.setState(999);
//        jsonResult.setMessage(message);
        //return  new JsonResult(999,message);
        //return new JsonResult().setState(999).setMessage(message);
        return JsonResult.fail(ServiceCode.ERR_UNKNOWN,message);
    }

}
